﻿using System;
using System.Collections.Generic;

using System.Text;

namespace Fetion.Core
{
    /// <summary>
    /// 数据流读取对象
    /// </summary>
    public class BufferReader 
    {
        internal IList<DataBuffer> mBuffers = new List<DataBuffer>(8);
        private int mIndex = 0;
        private DataBuffer mCursorBuffer;
        private int mCount = 0;

        private IByteConverter mByteConverter = new ByteConverter();
        /// <summary>
        /// 获取流总长度
        /// </summary>
        public int Count
        {
            get
            {
                return mCount;
            }
        }
        /// <summary>
        /// 获取流中所有数据
        /// </summary>
        /// <returns>byte[]</returns>
        public byte[] ToBytes()
        {
            byte[] result = new byte[Count];
            DataBuffer db;
            int index = 0;
            for (int i = 0; i < mBuffers.Count; i++)
            {
                db = mBuffers[i];
                Array.Copy(db.Data, 0, result, index, db.mCount);
                index += db.mCount;
            }
           
            return result;

        }
        internal BufferReader(Encoding coding, IList<DataBuffer> buffers)
        {
            mBuffers = buffers;
            Coding = coding;
            for (int i = 0; i < buffers.Count; i++)
            {
                mCount += buffers[i].mCount;
                buffers[i].Seek();
            }
           
            nextBuffer();
        }
        /// <summary>
        /// 构建流读取对象
        /// </summary>
        /// <param name="coding">字符编码</param>
        public BufferReader(Encoding coding)
        {
            Coding = coding;
        }
        DataBuffer _importdb;
       

        /// <summary>
        /// 构建流读取对象
        /// </summary>
        /// <param name="coding">字符编码</param>
        /// <param name="write">流写入对象</param>
        public BufferReader(Encoding coding, BufferWriter write)
        {
            Coding = coding;
          
            while (write.Buffers.Count > 0)
            {
                _importdb = write.Buffers.Dequeue();
                _importdb.Seek();
                mCount += _importdb.mCount;
                mBuffers.Add(_importdb);
            }
           
            nextBuffer();
        }
        /// <summary>
        /// 获取或设置流编码
        /// </summary>
        public Encoding Coding;        
        private void nextBuffer()
        {
            mCursorBuffer = mBuffers[mIndex];
            mIndex++;
        }
        /// <summary>
        /// 获取指定长度的数据
        /// </summary>
        /// <param name="count">长度</param>
        /// <returns>byte[]</returns>
        public byte[] ReadBytes(int count)
        {
            ByteArraySegment result = Read(count);
            if (result.Offset == 0 && result.Count == result.Array.Length)
                return result.Array;
            byte[] data = new byte[count];
            Buffer.BlockCopy(result.Array, result.Offset, data, 0, result.Count);
            return data;
        }
        /// <summary>
        /// 获取当前流的一个byte数组
        /// </summary>
        /// <returns>byte[]</returns>
        public byte[] ReadByteArray()
        {
            int length = ReadInt32();
            if (length > 0)
                return ReadBytes(length);
            return new byte[0];

        }
        private int _readcount = 0;
        private ByteArraySegment mRetusnByteArraySegment = new ByteArraySegment();
        private ByteArraySegment tmpByteArraySegment;
        /// <summary>
        /// 读取流中指定长度信息的引用
        /// </summary>
        /// <param name="count">长度</param>
        /// <returns>ByteArraySegment</returns>
        public ByteArraySegment Read(int count)
        {

            tmpByteArraySegment = mCursorBuffer.Read(count);
            if (tmpByteArraySegment.Count == count)
            {
                mRetusnByteArraySegment.SetInfo(tmpByteArraySegment.Array, tmpByteArraySegment.Offset, tmpByteArraySegment.Count);
                return mRetusnByteArraySegment;
            }
            _readcount = 0;
            byte[] data = new byte[count];
            while (true)
            {
                Buffer.BlockCopy(tmpByteArraySegment.Array, tmpByteArraySegment.Offset, data, _readcount, tmpByteArraySegment.Count);
                _readcount += tmpByteArraySegment.Count;
                if (_readcount >= count)
                    break;
                nextBuffer();
                tmpByteArraySegment = mCursorBuffer.Read(count - _readcount);
            }
            mRetusnByteArraySegment.SetInfo(data, 0, count);
            return mRetusnByteArraySegment;
         

        }
        private T[] createArray<T>()
        {
            T[] result = new T[ReadInt32()];
            return result;

        }
        private IList<T> createList<T>(out int count)
        {
            count = ReadInt32();
            List<T> list = new List<T>(count);
            return list;
        }
        /// <summary>
        /// 读取一个byte
        /// </summary>
        /// <returns>byte</returns>
        public byte ReadByte()
        {
            return mByteConverter.ReadByte(this);
        }
        /// <summary>
        /// 读取一个bool
        /// </summary>
        /// <returns>bool</returns>
        public bool ReadBool()
        {
            return mByteConverter.ReadBool(this);
        }
        /// <summary>
        /// 读取一个bool数组
        /// </summary>
        /// <returns>bool[]</returns>
        public bool[] ReadBools()
        {
            bool[] result = createArray<bool>();
            for (int i = 0; i < result.Length; i++)
            {
                result[i] = ReadBool();
            }
            return result;
        }
        /// <summary>
        /// 读取一个bool列表
        /// </summary>
        /// <returns>IList'bool</returns>
        public IList<bool> ReadBoolList()
        {
            int _count;
            IList<bool> result = createList<bool>(out _count);
            for (int i = 0; i < _count; i++)
            {
                result.Add(ReadBool());
            }
            return result;
        }
        /// <summary>
        /// 读取一个char
        /// </summary>
        /// <returns>char</returns>
        public char ReadChar()
        {
            return mByteConverter.ReadChar(this);
        }
        /// <summary>
        /// 读取一个char数组
        /// </summary>
        /// <returns>char[] </returns>
        public char[] ReadChars()
        {
            char[] result = createArray<char>();
            for (int i = 0; i < result.Length; i++)
            {
                result[i] = ReadChar();
            }
            return result;
        }
        /// <summary>
        /// 读取一个char列表
        /// </summary>
        /// <returns>IList'char</returns>
        public IList<char> ReadCharList()
        {
            int _count;
            IList<char> result = createList<char>(out _count);
            for (int i = 0; i < _count; i++)
            {
                result.Add(ReadChar());
            }
            return result;
        }
        /// <summary>
        /// 读取一个double
        /// </summary>
        /// <returns>double</returns>
        public double ReadDouble()
        {
            if (EnabledVariant)
            {
                long num = Read64Variant();
                return BitConverter.ToDouble(BitConverter.GetBytes(num), 0);
            }
            else
                return mByteConverter.ReadDouble(this);
        }
        /// <summary>
        /// 读取一个double数组
        /// </summary>
        /// <returns>double[]</returns>
        public double[] ReadDoubles()
        {
            double[] result = createArray<double>();
            for (int i = 0; i < result.Length; i++)
            {
                result[i] = ReadDouble();
            }
            return result;
        }
        /// <summary>
        /// 读取一个double列表
        /// </summary>
        /// <returns>IList'double</returns>
        public IList<double> ReadDoubleList()
        {
            int _count = 0;
            IList<double> result = createList<double>(out _count);
            for (int i = 0; i < _count; i++)
            {
                result.Add(ReadDouble());
            }
            return result;
        }
        /// <summary>
        /// 读取一个int16
        /// </summary>
        /// <returns>Int16</returns>
        public Int16 ReadInt16()
        {
            return mByteConverter.ReadInt16(this);
        }
        /// <summary>
        /// 读取一个int16数组
        /// </summary>
        /// <returns>Int16[]</returns>
        public Int16[] ReadInt16s()
        {
            Int16[] result = createArray<Int16>();
            for (int i = 0; i < result.Length; i++)
            {
                result[i] = ReadInt16();
            }
            return result;
        }
        /// <summary>
        /// 读取一个int16列表
        /// </summary>
        /// <returns>IList'Int16</returns>
        public IList<Int16> ReadInt16List()
        {
            int _count;
            IList<Int16> result = createList<Int16>(out _count);
            for (int i = 0; i < _count; i++)
            {
                result.Add(ReadInt16());
            }
            return result;
        }
        /// <summary>
        /// 读取一个int32
        /// </summary>
        /// <returns>Int32</returns>
        public Int32 ReadInt32()
        {
            if (EnabledVariant)
                return Read32Variant();
            return mByteConverter.ReadInt32(this);
        }
        /// <summary>
        /// 读取一个int32数组
        /// </summary>
        /// <returns>Int32[]</returns>
        public Int32[] ReadInt32s()
        {
            Int32[] result = createArray<Int32>();
            for (int i = 0; i < result.Length; i++)
            {
                result[i] = ReadInt32();
            }
            return result;
        }
        /// <summary>
        /// 读取一个int32列表
        /// </summary>
        /// <returns>IList'Int32</returns>
        public IList<Int32> ReadInt32List()
        {
            int _count;
            IList<Int32> result = createList<Int32>(out _count);
            for (int i = 0; i < _count; i++)
            {
                result.Add(ReadInt32());
            }
            return result;
        }
        /// <summary>
        /// 获取一个int64
        /// </summary>
        /// <returns></returns>
        public Int64 ReadInt64()
        {
            if (EnabledVariant)
                return Read64Variant();
            return mByteConverter.ReadInt64(this);
        }
        /// <summary>
        /// 获取一个int64数组
        /// </summary>
        /// <returns>Int64[]</returns>
        public Int64[] ReadInt64s()
        {
            Int64[] result = createArray<Int64>();
            for (int i = 0; i < result.Length; i++)
            {
                result[i] = ReadInt64();
            }
            return result;
        }
        /// <summary>
        /// 获取一个int64列表
        /// </summary>
        /// <returns>IList'Int64</returns>
        public IList<Int64> ReadInt64List()
        {
            int _count;
            IList<Int64> result = createList<Int64>(out _count);
            for (int i = 0; i < _count; i++)
            {
                result.Add(ReadInt64());
            }
            return result;
        }
        /// <summary>
        /// 获取一个float
        /// </summary>
        /// <returns>float</returns>
        public float ReadFloat()
        {
            if (EnabledVariant)
            {
                int num = Read32Variant();
                return BitConverter.ToSingle(BitConverter.GetBytes(num), 0);
            }
            else
                return mByteConverter.ReadFloat(this);
        }
        /// <summary>
        /// 获取一个float数组
        /// </summary>
        /// <returns>float[]</returns>
        public float[] ReadFloats()
        {
            float[] result = createArray<float>();
            for (int i = 0; i < result.Length; i++)
            {
                result[i] = ReadFloat();
            }
            return result;
        }
        /// <summary>
        /// 获取一个float列表
        /// </summary>
        /// <returns>IList'float</returns>
        public IList<float> ReadFloatList()
        {
            int _count;
            IList<float> result = createList<float>(out _count);
            for (int i = 0; i < _count; i++)
            {
                result.Add(ReadFloat());
            }
            return result;
        }
        /// <summary>
        /// 获取一个datetime
        /// </summary>
        /// <returns>datetime</returns>
        public DateTime ReadDate()
        {
            long date = mByteConverter.ReadInt64(this);
            return new DateTime(date);
        }
        /// <summary>
        /// 获取一个datetime数组
        /// </summary>
        /// <returns>datetime[]</returns>
        public DateTime[] ReadDates()
        {
            DateTime[] result = createArray<DateTime>();
            for (int i = 0; i < result.Length; i++)
            {
                result[i] = ReadDate();
            }
            return result;
        }
        /// <summary>
        /// 获取一个时间列表
        /// </summary>
        /// <returns>IList'DateTime</returns>
        public IList<DateTime> ReadDateTimeList()
        {
            int _count = 0;
            IList<DateTime> result = createList<DateTime>(out _count);
            for (int i = 0; i < _count; i++)
            {
                result.Add(ReadDate());
            }
            return result;
        }
        /// <summary>
        /// 获取一个字符串
        /// </summary>
        /// <returns>string</returns>
        public string ReadString()
        {
            int length = ReadInt32();
        
            if (length > 0)
                return ReadString(length);
            return null;
        }
        /// <summary>
        /// 获取一个字符串数组
        /// </summary>
        /// <returns>string[]</returns>
        public string[] ReadStrings()
        {
            string[] result = createArray<string>();
            for (int i = 0; i < result.Length; i++)
            {
                result[i] = ReadString();
            }
            return result;
        }
        /// <summary>
        /// 获取一个字符串列表
        /// </summary>
        /// <returns>IList'string</returns>
        public IList<string> ReadStringList()
        {
            int _count;
            IList<string> result = createList<string>(out _count);
            for (int i = 0; i < _count; i++)
            {
                result.Add(ReadString());
            }
            return result;
        }
       
        /// <summary>
        /// 获取一个消息对象
        /// </summary>
        /// <typeparam name="T">消息类型</typeparam>
        /// <returns>消息对象</returns>
        public T ReadObject<T>() where T : IMessage, new()
        {
            T item = new T();
            item.Load(this);
            return item;
        }
       
        /// <summary>
        /// 获取一个对象列表
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <returns>IList'T</returns>
        public IList<T> ReadObjects<T>() where T : IMessage, new()
        {
            int count = ReadInt32();
            List<T> items = new List<T>(count);

            for (int i = 0; i < count; i++)
            {
                items.Add(ReadObject<T>());
            }
            return items;

        }

        /// <summary>
        /// 获取指定长度的string
        /// </summary>
        /// <param name="count">长度</param>
        /// <returns>string</returns>
        public string ReadString(int count)
        {
            ByteArraySegment data = Read(count);
            string result = Coding.GetString(data.Array, data.Offset, data.Count);//.Decoding(data, Coding); //Coding.GetString(data.Array, data.Offset, count);
            return result;
        }
        #region ReadVariant
        /// <summary>
        /// 是否开启Variant方式读取int,int64，默认是false
        /// </summary>
        public bool EnabledVariant = false;
        private int Read32Variant()
        {
            return Zag(ReadUInt32Variant());
        }
        private long Read64Variant()
        {
            return Zag(ReadUInt64Variant());
        }
        private const int Int32Msb = ((int)1) << 31;
        private const long Int64Msb = ((long)1) << 63;
        private int Zag(uint ziggedValue)
        {
            int value = (int)ziggedValue;
            return (-(value & 0x01)) ^ ((value >> 1) & ~Int32Msb);
        }
        private long Zag(ulong ziggedValue)
        {
            long value = (long)ziggedValue;
            return (-(value & 0x01L)) ^ ((value >> 1) & ~Int64Msb);
        }
        private uint ReadUInt32Variant()
        {
            uint value = ReadByte();
            if ((value & 0x80) == 0) return value;
            value &= 0x7F;
            uint chunk = ReadByte();
            value |= (chunk & 0x7F) << 7;
            if ((chunk & 0x80) == 0) return value;
            chunk = ReadByte();
            value |= (chunk & 0x7F) << 14;
            if ((chunk & 0x80) == 0) return value;
            chunk = ReadByte();
            value |= (chunk & 0x7F) << 21;
            if ((chunk & 0x80) == 0) return value;
            chunk = ReadByte();
            value |= chunk << 28;
            if ((chunk & 0xF0) == 0) return value;
            throw new OverflowException("ReadUInt32Variant Error!");
        }
        private ulong ReadUInt64Variant()
        {

            ulong value = ReadByte();
            if ((value & 0x80) == 0) return value;
            value &= 0x7F;
            ulong chunk = ReadByte();
            value |= (chunk & 0x7F) << 7;
            if ((chunk & 0x80) == 0) return value;
            chunk = ReadByte();
            value |= (chunk & 0x7F) << 14;
            if ((chunk & 0x80) == 0) return value;
            chunk = ReadByte();
            value |= (chunk & 0x7F) << 21;
            if ((chunk & 0x80) == 0) return value;
            chunk = ReadByte();
            value |= (chunk & 0x7F) << 28;
            if ((chunk & 0x80) == 0) return value;
            chunk = ReadByte();
            value |= (chunk & 0x7F) << 35;
            if ((chunk & 0x80) == 0) return value;
            chunk = ReadByte();
            value |= (chunk & 0x7F) << 42;
            if ((chunk & 0x80) == 0) return value;
            chunk = ReadByte();
            value |= (chunk & 0x7F) << 49;
            if ((chunk & 0x80) == 0) return value;
            chunk = ReadByte();
            value |= (chunk & 0x7F) << 56;
            if ((chunk & 0x80) == 0) return value;
            chunk = ReadByte();
            value |= chunk << 63;
            if ((chunk & ~(ulong)0x01) == 0) return value;
            throw new OverflowException("ReadUInt64Variant Error!");
        }
        #endregion

    }
}
